package carAgents;

import jade.core.Agent;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;

import java.util.*;

public class OfferAgent extends Agent {
  private Hashtable<Point, Point> catalogue;
  private OfferAgentGui myGui;

  protected void setup() {
    catalogue = new Hashtable();
    myGui = new OfferAgentGui(this);
    myGui.display();

    //registration of offer in df catalogue
    DFAgentDescription dfd = new DFAgentDescription();
    dfd.setName(getAID());
    ServiceDescription sd = new ServiceDescription();
    sd.setType("car-offer");
    sd.setName("JADE-car-offer");
    dfd.addServices(sd);
    try {
      DFService.register(this, dfd);
    }
    catch (FIPAException fe) {
      fe.printStackTrace();
    }
    
    addBehaviour(new OfferRequestsServer());

    addBehaviour(new PurchaseOrdersServer());
  }

  protected void takeDown() {
    //remove offer from the df catalogue
    try {
      DFService.deregister(this);
    }
    catch (FIPAException fe) {
      fe.printStackTrace();
    }
  	myGui.dispose();
    System.out.println("Offering agent "+getAID().getName()+" has finished.");
  }

  //method called by gui when new offer is added
  public void updateCatalogue(final Point startP, final Point goalP) {
    addBehaviour(new OneShotBehaviour() {
      public void action() {
		catalogue.put(startP, goalP);
		System.out.println("Offer of journey from: "+startP.getCountry()+
				" "+startP.getCity()+
				" "+startP.getStreet()+
				" to "+goalP.getCountry()+
				" "+goalP.getCity()+
				" "+goalP.getStreet()+" was added to catalogue.");
      }
    } );
  }
  
	private class OfferRequestsServer extends CyclicBehaviour {
	  public void action() {
	    //only offers
		MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP);
		ACLMessage msg = myAgent.receive(mt);
	    if (msg != null) {
	      String startP = msg.getContent();
	      ACLMessage reply = msg.createReply();
	      Point goalP = (Point) catalogue.get(startP);
	      if (goalP != null) {
	        //there start point exist
	    	//TODO:porównywanie trzech wartości a nie tylko jednej
	        reply.setPerformative(ACLMessage.PROPOSE);
	        reply.setContent(String.valueOf(goalP));
	      }
	      else {
	        //no offer in catalogue
	        reply.setPerformative(ACLMessage.REFUSE);
	        reply.setContent("not-available");
	      }
	      myAgent.send(reply);
	    }
	    else {
	      block();
	    }
	  }
	}

	
	private class PurchaseOrdersServer extends CyclicBehaviour {
	  public void action() {
		  //only accepted offers
		MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL);
		ACLMessage msg = myAgent.receive(mt);
	    if (msg != null) {
	      String startP = msg.getContent();
	      ACLMessage reply = msg.createReply();
	      Point goalP = (Point) catalogue.remove(startP);
	      if (goalP != null) {
	        reply.setPerformative(ACLMessage.INFORM);
	        System.out.println("Jounrey from "+startP+" to "+goalP+" given to "+msg.getSender().getLocalName());
	      }
	      else {
	        //no offer in the catalogue, already sold
	        reply.setPerformative(ACLMessage.FAILURE);
	        reply.setContent("not-available");
	      }
	      myAgent.send(reply);
	    }
	    else {
		  block();
		}
	  }
	}

}

